﻿/********************************************************************************************************

	The Truveo Video Search Flash API version 3.
	Copyright (c) 2007, Truveo LLC.
	All rights reserved.
	
********************************************************************************************************/

import mx.events.EventDispatcher;
import mx.utils.Delegate;
import mx.xpath.XPathAPI;

/////////////////////////////////////////////////////////////////////////////////////////
// The TruveoVideoSearch class is the top-level class for the Truveo Video Search Flash API. 
/////////////////////////////////////////////////////////////////////////////////////////
class TruveoVideoSearch
{
	///// Member variables with get and/or set privileges
	// Request attributes
	private var _appID:String;					// application ID
	private var _results:Number = 10;			// number of results to be returned
	private var _tagResults:Number = 10;		// number of related tags to be returned
	private var _channelResults:Number = 10;  	// number of related channels to be returned
	private var _categoryResults:Number = 10;  	// number of related categories to be returned
	private var _userResults:Number = 10;  		// number of related users to be returned
	private var _showRelatedItems:Number = 0;  	// flag that indicates if related tags, channels, categories and users should be returned
	private var _showAdult:Number = 0;  		// flag that indicates if adult content should be included in result set
	private var _start:Number = 0;				// starting position of the first result
	
	// Response attributes
	private var _method:String;   			// string containing the name of the API method
	private var _query:String;    			// string containing the query that was submitted
	private var _querySuggestion:String;  	// string containing a suggested query (if available)
	private var _videoSet:Object = null;
	private var _tagSet:Object = null;
	private var _categorySet:Object = null;
	private var _channelSet:Object = null;
	private var _userSet:Object = null;
	private var _Result:Object = null;

	///// Private member variables
	private var _xmlDoc:XML;   	// XML document representing the response
	
	// Event objects
	private var _onUpdateEvent:Object = new Object();  // represents "onupdate" event
	private var _onErrorEvent:Object = new Object();   // represents "onerror" event
	private var _onLoadEvent:Object = new Object();    // represents "onload" event
	
	// Error messages
	private var _errorMessages:Object = {code_502: "Invalid Flash method call: The wrong number of arguments was provided to this method.",
										 code_503: "Method not available: You must be logged in to use this method.",
										 code_400: "Bad API request or API Service unavailable. Check that the parameters to the request are correctly specified."};

	// Constructor for TruveoVideoSearch object.
	// Parameters:
	//		appID (required): application ID against which all queries will be executed
	public function TruveoVideoSearch(appID:String) {
		_appID = appID;
		
		// initialize event dispatcher
		mx.events.EventDispatcher.initialize(this);
		
		// initialize event objects
		_onUpdateEvent.target=this;
		_onUpdateEvent.type="onupdate";
		_onErrorEvent.target=this;
		_onErrorEvent.type="onerror";
		_onLoadEvent.target=this;
		_onLoadEvent.type="onload";
	}
	
	/**************************************************************************************************
	PUBLIC functions that implement APIv3
	***************************************************************************************************/
	
	// Function initialize()
	// Nothing here yet: needed for user-methods
	// Events:
	//		onload: This event will be dispatched once the initialization of this object has completed.
	// Return value: (none)
	public function initialize():Void {
		// Throw 'onload' event immediately
		// Set reloadStateFlag to false for now; this is only true if this object was initialized following a return from the
		// Truveo account login page.
		_onLoadEvent.reloadStateFlag = false;
		dispatchEvent(_onLoadEvent);
	}
	
	// Implements API method: truveo.videos.getVideos
	// Parameters: 
	//		query (optional; defaults to ""): the query to execute.  This should follow the format specified in http://developer.truveo.com/SearchQueryOverview.php
	//		start (optional; defaults to 0): the starting position of the first result
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.
	public function getVideos(query:String, start:Number):Boolean {
		if (query == null) query="";  // default to empty query
		if (start == null) start=0;   // default to start position of 0
		
		submitRESTQuery({method: "truveo.videos.getVideos", 
						query: query, 
						results: _results,
						start: start,
						showRelatedItems: _showRelatedItems,
						tagResults: _tagResults,
						channelResults: _channelResults,
						categoryResults: _categoryResults,
						userResults: _userResults,
						showAdult: _showAdult});
		return(true);
	}
	
	// Implements API method: truveo.videos.getRelatedTags
	// Parameters: 
	//		query (optional; defaults to ""): the query to execute.  This should follow the format specified in http://developer.truveo.com/SearchQueryOverview.php
	//		start (optional; defaults to 0): the starting position of the first result
	//		results (optional; defaults to 10): the number of results the search engine should return; if set, overrides tagResults property
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.
	public function getRelatedTags(query:String, start:Number, results:Number):Boolean {
		if (query == null) query="";  // default to empty query
		if (start == null) start=0;   // default to start position of 0
		if (results == null) results=_tagResults;  // default # of results to value of tagResults property
		
		submitRESTQuery({method: "truveo.videos.getRelatedTags", 
						query: query, 
						results: results,
						start: start});
		return(true);
	}
	
	// Implements API method: truveo.videos.getRelatedChannels
	// Parameters: 
	//		query (optional; defaults to ""): the query to execute.  This should follow the format specified in http://developer.truveo.com/SearchQueryOverview.php
	//		start (optional; defaults to 0): the starting position of the first result
	//		results (optional; defaults to 10): the number of results the search engine should return; if set, overrides channelResults property
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.
	public function getRelatedChannels(query:String, start:Number, results:Number):Boolean {
		if (query == null) query="";  // default to empty query
		if (start == null) start=0;   // default to start position of 0
		if (results == null) results=_channelResults;  // default # of results to value of channelResults property
		
		submitRESTQuery({method: "truveo.videos.getRelatedChannels", 
						query: query, 
						results: results,
						start: start});
		return(true);
	}
	
	// Implements API method: truveo.videos.getRelatedCategories
	// Parameters: 
	//		query (optional; defaults to ""): the query to execute.  This should follow the format specified in http://developer.truveo.com/SearchQueryOverview.php
	//		start (optional; defaults to 0): the starting position of the first result
	//		results (optional; defaults to 10): the number of results the search engine should return; if set, overrides categoryResults property
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.
	public function getRelatedCategories(query:String, start:Number, results:Number):Boolean {
		if (query == null) query="";  // default to empty query
		if (start == null) start=0;   // default to start position of 0
		if (results == null) results=_categoryResults;  // default # of results to value of categoryResults property
		
		submitRESTQuery({method: "truveo.videos.getRelatedCategories", 
						query: query, 
						results: results,
						start: start});
		return(true);
	}
	
	// Implements API method: truveo.videos.getRelatedUsers
	// Parameters: 
	//		query (optional; defaults to ""): the query to execute.  This should follow the format specified in http://developer.truveo.com/SearchQueryOverview.php
	//		start (optional; defaults to 0): the starting position of the first result
	//		results (optional; defaults to 10): the number of results the search engine should return; if set, overrides userResults property
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.
	public function getRelatedUsers(query:String, start:Number, results:Number):Boolean {
		if (query == null) query="";  // default to empty query
		if (start == null) start=0;   // default to start position of 0
		if (results == null) results=_userResults;  // default # of results to value of userResults property
		
		submitRESTQuery({method: "truveo.videos.getRelatedUsers", 
						query: query, 
						results: results,
						start: start});
		return(true);
	}
	
	// Implements API method: truveo.videos.submitRating
	// Parameters: 
	//		id (required): the unique id value for an available video in the search engine
	//		rating (required): the rating to be assigned to the given video.  Must be number between 0 and 5.
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.  'false' if this function is called with the incorrect number
	//		of arguments.
	public function submitRating(id:Number, rating:Number):Boolean {
		if (arguments.length < 2) {
			_onErrorEvent.errorCode = 502;
			_onErrorEvent.errorMessage = _errorMessages["code_502"];
			dispatchEvent(_onErrorEvent);
			return(false);
		}
		
		submitRESTQuery({method: "truveo.videos.submitRating", 
						id: id, 
						rating: rating});
		return(true);
	}	
	
	// Implements convenience method: hasNextPage
	// Parameters: (none)
	// Events: (none)
	// Return value:
	//		'true' if another page of video search results is available; needs to be called after a call to getVideos()
	public function hasNextPage():Boolean {
		if (_videoSet) {
			return ((parseInt(_videoSet["firstResultPosition"]) + parseInt(_videoSet["totalResultsReturned"])) 
					< parseInt(_videoSet["totalResultsAvailable"]));
		}
		return false;
	}
	
	// Implements convenience method: hasPreviousPage
	// Parameters: (none)
	// Events: (none)
	// Return value:
	//		'true' if a previous page of video search results is available; needs to be called after a call to getVideos()
	public function hasPreviousPage():Boolean {
		if (_videoSet) {
			return (parseInt(_videoSet["firstResultPosition"]) > 0);
		}
		return false;
	}
	
	// Implements convenience method: nextPage
	// Parameters: (none)
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.  'false' if there is no VideoSet available.
	// Retrieves the VideoSet containing the next page of video search results.
	public function nextPage() {
		if (_videoSet) {
			var newStartPosition = parseInt(_videoSet["firstResultPosition"]) + parseInt(_videoSet["totalResultsReturned"]);
			getVideos(_query, newStartPosition);
			return(true);
		}
		return(false);
	}
	
	// Implements convenience method: previousPage
	// Parameters: (none)
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.  'false' if there is no VideoSet available.
	// Retrieves the VideoSet containing the previous page of video search results.
	public function previousPage() {
		if (_videoSet) {
			var newStartPosition = parseInt(_videoSet["firstResultPosition"]) - _results;
			getVideos(_query, newStartPosition);
			return(true);
		}
		return(false);
	}
	
	// Implements convenience method: goToPage
	// Parameters:
	//		pageNum (required):  The page number of the video results to return.
	// Events:
	//		onupdate:  This event will be dispatched when the XML results have been received, the XML has been successfully parsed, and the VideoSet
	//					object has been populated.
	//		onerror:   This event will be dispatched when the XML results include an Error.
	// Return value:
	//		'true' if the XML API request was sent successfully.  'false' if there is no VideoSet available.
	// Retrieves the page of the VideoSet specified by the pageNum.
	public function goToPage(pageNum:Number) {
		if (_videoSet) {
			var newStartPosition = (pageNum-1) * _results;
			newStartPosition = (newStartPosition < 0 ? 0 : newStartPosition);
			getVideos(_query, newStartPosition);
			return(true);
		}
		return(false);
	}
	
	/**************************************************************************************************
	PUBLIC attributes available in APIv3
	***************************************************************************************************/
	
	// VideoSet (read-only)
	// Type: Object
	// This Object is defined here: http://developer.truveo.com/AJAXAPIDataObject.php?name=VideoSet.
	// It may have 0 length.
	function get VideoSet():Object {
		return _videoSet;
	}
	
	// TagSet (read-only)
	// Type: Object
	// This Object is defined here: http://developer.truveo.com/AJAXAPIDataObject.php?name=TagSet.
	// It may have 0 length.  It may be null.
	function get TagSet():Object {
		return _tagSet;
	}
	
	// CategorySet (read-only)
	// Type: Object
	// This Object is defined here: http://developer.truveo.com/AJAXAPIDataObject.php?name=CategorySet.
	// It may have 0 length.  It may be null.
	function get CategorySet():Object {
		return _categorySet;
	}
	
	// ChannelSet (read-only)
	// Type: Object
	// This Object is defined here: http://developer.truveo.com/AJAXAPIDataObject.php?name=ChannelSet.
	// It may have 0 length.  It may be null.
	function get ChannelSet():Object {
		return _channelSet;
	}	
	
	// UserSet (read-only)
	// Type: Object
	// This Object is defined here: http://developer.truveo.com/AJAXAPIDataObject.php?name=UserSet.
	// It may have 0 length.  It may be null.
	function get UserSet():Object {
		return _userSet;
	}
	
	// Result (read-only)
	// Type: Object
	// This Object is defined here: http://developer.truveo.com/AJAXAPIDataObject.php?name=Result.
	// It may be null.	
	function get Result():Object {
		return _Result;
	}
	
	// results (read/write)
	// Type: Number
	// The number of results that the XML API will attempt to return in response to the query.
	// Valid values are integers in [1, 50].
	function get results():Number {
		return _results;
	}
	function set results(new_val:Number):Void {
		_results = new_val;
	}
	
	// start (read/write)
	// Type: Number
	// The starting position of the first result that the XML API will attempt to return in response to the query.
	// Valid value is any integer >= 0.
	function get start():Number {
		return _start;
	}
	function set start(new_val:Number):Void {
		_start = new_val;
	}
	
	// tagResults (read/write)
	// Type: Number
	// The number of related tags that the XML API will attempt to return in response to the query.  Only relevant
	// if 'showRelatedItems' is set to 1.
	// Valid value is an integer in [1, 50].	
	function get tagResults():Number {
		return _tagResults;
	}
	function set tagResults(new_val:Number):Void {
		_tagResults = new_val;
	}
	
	// channelResults (read/write)
	// Type: Number
	// The number of related channels that the XML API will attempt to return in response to the query.  Only relevant
	// if 'showRelatedItems' is set to 1.
	// Valid value is an integer in [1, 50].
	function get channelResults():Number {
		return _channelResults;
	}
	function set channelResults(new_val:Number):Void {
		_channelResults = new_val;
	}
	
	// categoryResults (read/write)
	// Type: Number
	// The number of related categories that the XML API will attempt to return in response to the query.  Only relevant
	// if 'showRelatedItems' is set to 1.
	// Valid value is an integer in [1, 50].
	function get categoryResults():Number {
		return _categoryResults;
	}
	function set categoryResults(new_val:Number):Void {
		_categoryResults = new_val;
	}
	
	// userResults (read/write)
	// Type: Number
	// The number of related users that the XML API will attempt to return in response to the query.  Only relevant
	// if 'showRelatedItems' is set to 1.
	// Valid value is an integer in [1, 50].	
	function get userResults():Number {
		return _userResults;
	}
	function set userResults(new_val:Number):Void {
		_userResults = new_val;
	}
	
	// showRelatedItems(read/write)
	// Type: Number
	// Flag that indicates if related tags, channels, categories and users should be included in the result set.  
	// Valid value is one of {0, 1}.
	function get showRelatedItems():Number {
		return _showRelatedItems;
	}
	function set showRelatedItems(new_val:Number):Void {
		_showRelatedItems = new_val;
	}
	
	// showAdult (read/write)
	// Type: Number
	// Flag that indicates if adult content should be included in the result set.  
	// Valid value is one of {0, 1}.
	function get showAdult():Number {
		return _showAdult;
	}
	function set showAdult(new_val:Number):Void {
		_showAdult = new_val;
	}
	
	// method (read-only)
	// Type: String
	// A string containing the name of the API method used to retrieve the response.
	function get method():String {
		return _method;
	}
	
	// query (read-only)
	// Type: String
	// A string containing the original submitted query associated with this response.
	function get query():String {
		return _query;
	}
	
	// querySuggestion (read-only)
	// Type: String
	// A string containing a suggested query, if available, for the original submitted query associated with this response.
	// May be undefined.
	function get querySuggestion():String {
		return _querySuggestion;
	}
	
	/**************************************************************************************************
	PRIVATE functions 
	***************************************************************************************************/
	
	// Function processQueryResults() will be called once the XML API has returned and the XML document has been loaded.  
	// This function parses the resulting XML and populates the _videoSet, _tagSet, _categorySet, _channelSet and _userSet
	// objects.  See comments for parseXMLSet() for details on how these *Set objects are structured.
	// Throws the "onupdate" event after the XML has been received and successfully parsed.  In the response contains
	// an Error node, the "onerror" event will be thrown.
	private function processQueryResults(bSuccess:Boolean) {
		if (bSuccess) {  // XML was sucessfully loaded
			_videoSet = new Object();
			var rootNode:XMLNode = _xmlDoc.firstChild; // <Response>
			
			// Get attributes of the Response element: method, query, querySuggestion
			parseResponseAttributes(rootNode);
			
			// Convert XML for VideoSet to an object representation			
			_videoSet = parseXMLSet(rootNode, "Video");
			
			// Convert XML for TagSet to an object representation
			_tagSet = parseXMLSet(rootNode, "Tag");
			
			// Convert XML for CategorySet to an object representation
			_categorySet = parseXMLSet(rootNode, "Category");
			
			// Convert XML for ChannelSet to an object representation
			_channelSet = parseXMLSet(rootNode, "Channel");
			
			// Convert XML for UserSet to an object representation
			_userSet = parseXMLSet(rootNode, "User");
			
			// Convert XML for Result to an object representation
			_Result = parseResult(rootNode);
		}
		else {
			// This means either the XML API service couldn't be contacted, or the API returned an error.  When the
			// API returns an error, the HTTP response code will be one of: Bad request 400, Forbidden 403 or Service
			// Unavailable 503.  All of these are interpreted as 'bSuccess==false' in Flash.
			trace ("TruveoVideoSearch.processQueryResults(): Error loading XML or Error in API request.");
			//parseXMLError(_xmlDoc.firstChild);  // get the error code + message that the API returned
			// Note: the Flash XML class throws away the response body if the HTTP response is a non-200
			// status code.  As a result, the API will throw a generic error for all non-200 responses from the API.
			_onErrorEvent.errorCode = 400;
			_onErrorEvent.errorMessage = _errorMessages["code_400"];
			dispatchEvent(_onErrorEvent);  // throw the "onerror" event
			return;
		}
	 
		
		_onUpdateEvent.methodName = _method;
		dispatchEvent(_onUpdateEvent);
	}
	
	// Function parseResult parses the XML response from methods that return a <Result> element (submitRating, addFavorite).
	// The returned object is an associative array.
	private function parseResult(rootNode:XMLNode) {
		var resultObj = new Object();
		
		// Convert XML for Result to an object representation
		var resultElt:XMLNode = XPathAPI.selectSingleNode(rootNode, "/Response/Result");
		for (var curNode=resultElt.firstChild; curNode != null; curNode=curNode.nextSibling) {
			resultObj[curNode.nodeName] = curNode.firstChild.nodeValue;
		}
		
		return resultObj;
	}
	
	// Function parseXMLSet() parses the XML for a given Set node and returns an object representation.
	// The Set node is determined by the given 'setType' string, which must be one of: {Video, Tag, Category, Channel, User}.
	// Set nodes (i.e., <VideoSet>, <TagSet>, <CategorySet>, <ChannelSet>, or <UserSet>) are structured in
	// the following way: they may have any number of child nodes at one level deep that correspond to attributes of the
	// Set.  These attributes will be stored as properties of the returned object (that can be accessed as if the object is
	// an associative array).  These are followed by the elements for that Set, which are all one level deep children of the root set node.
	// The names of these element tags should match the given 'setType' string: e.g., for a VideoSet these elements are
	// called <Video>.  The elements will be stored in an array that is a property of the returned object.  The array
	// will be named according to the given setType.  Each element in the array is an associative array of all the properties
	// set for that particular element node.
	private function parseXMLSet(rootNode:XMLNode, setType:String):Object {
		var setResult:Object = null;
		var xmlTagName = setType + "Set";  // will be: VideoSet, TagSet, ChannelSet or CategorySet
		
		// Convert XML for this Set to an object representation
		// Get the root xml node for this set
		var setRoot:XMLNode = XPathAPI.selectSingleNode(rootNode, "/Response/" + xmlTagName); 
		
		if (setRoot) {
			setResult = new Object();
			
			// First get attributes of this Set
			for (var curNode = setRoot.firstChild; curNode != null; curNode=curNode.nextSibling) {
				if (curNode.nodeName != setType) {
					setResult[curNode.nodeName] = curNode.firstChild.nodeValue;
				}
			}
			
			// Next get all Video/Tag/Channel/Category elements in this Set: populate setResult[setType] object as an array of hashes
			setResult[setType] = [];
			var elements:Array = XPathAPI.selectNodeList(rootNode, "/Response/" + xmlTagName + "/" + setType);
			for (var i=0; i<elements.length; i++) {
				setResult[setType].push({});
				for (var curNode = elements[i].firstChild; curNode != null; curNode=curNode.nextSibling) {
					setResult[setType][i][curNode.nodeName] = curNode.firstChild.nodeValue;
					//trace (curNode.nodeName + ": " + setResult[i][curNode.nodeName]);
				}
			}
		}
		
		return setResult;
	}
	
	// Function parseResponseAttributes() parses the <method>, <query> and <querySuggestion> tags.
	// These tags are children of the <Response> tag.  The <method> will be parsed so that only 
	// the name of the method (everything after the last '.') will be saved.  If the <query> tag
	// has no value, assume it was the empty query.  Also the <querySuggestion> field may not necessarily
	// be present in the response.  This method populates the _method, _query, and _querySuggestion
	// member variables.
	private function parseResponseAttributes(rootNode:XMLNode):Void {
		// Get attributes of the Response element: method, query, querySuggestion
		var responseAttrNode:XMLNode = XPathAPI.selectSingleNode(rootNode, "/Response/method");  // <method>
		if (responseAttrNode.firstChild) {
			// 'method' field should be just the name of the method, not full path
			_method=responseAttrNode.firstChild.nodeValue;
			_method=_method.slice(_method.lastIndexOf(".")+1);
		}
		responseAttrNode = XPathAPI.selectSingleNode(rootNode, "/Response/query");  // <query>
		if (responseAttrNode.firstChild) {
			_query=responseAttrNode.firstChild.nodeValue;
		}
		else {
			// if <query> element has no value, assume empty query
			_query="";
		}
		responseAttrNode = XPathAPI.selectSingleNode(rootNode, "/Response/querySuggestion");  // <querySuggestion>
		if (responseAttrNode.firstChild) {
			_querySuggestion=responseAttrNode.firstChild.nodeValue;
		}
	}
	
	// Function parseXMLError() returns true if the <Response> contains an <Error> element.  It will also update
	// the _onErrorEvent object.  Otherwise it returns false.
	private function parseXMLError(rootNode:XMLNode):Boolean {
		var bHasError = false;
		
		var errorNode:XMLNode= XPathAPI.selectSingleNode(rootNode, "/Response/Error");  // <Error>
		if (errorNode) {
			bHasError = true;
			_onErrorEvent.errorCode = errorNode.attributes.Code;
			_onErrorEvent.errorMessage = errorNode.firstChild.nodeValue;
		}
		
		return bHasError;
	}
	
	// Function submitRESTQuery() issues the request to the XML API with the given parameters in the 'params' hash.
	// The function processQueryResults() will be invoked when the XML has been loaded (or when there is an error).
	private function submitRESTQuery(params:Object) {
		_xmlDoc = new XML();
		
		_xmlDoc.onLoad = Delegate.create(this, processQueryResults);  // use delegate to preserve scope for event dispatching	
		
		_xmlDoc.load(constructRESTUrl(params));
	}
	
	// Function constructRESTUrl() returns the URL that, when requested, will query the REST XML API with 
	// the given parameters (params object) and the application ID with which this object was initialized.
	private function constructRESTUrl(params:Object):String {
		var restQuery:String = "http://xml.truveo.com/apiv3?appid=" + _appID;
		
		for (var param_name in params) {
			restQuery += "&" + param_name + "=" + escape(params[param_name]);
		}
		
		return restQuery;
	}
	
	// declare functions/variables to satisfy EventDispatcher class
	function dispatchEvent() {};
	function addEventListener() {};
	function removeEventListener() {};
}